#######################################################
# Example of CDEVS for two-slot toaster
# Author: moonho.hwang@gmail.com
#   Date: Oct.19.2011
#######################################################

from XSY.DEVS.CDEVS import * 
from XSY.DEVS.SimEngine import SimEngine
from XSY.DEVS.CoupledDEVS import *
from XSY.Set.Interval import *

class TwoSlotToaster(CDEVS):
   '''an atomic CDEVS for a two-slot toaster with two-different uniform pdf toasting times'''
   def __init__(self, n, parent):
      '''constructor'''
      CDEVS.__init__(self, n, {"t1":float('inf'), "t2":float('inf')}, parent)
      self.addInputPorts("?push1", '?push2')
      self.addOutputPorts("!pop1", '!pop2')
      self.toast_times = {"t1":TInterval(10,20), "t2":TInterval(15,30)}

   def delta_0(self):
      '''initialize function'''
      CDEVS.delta_0(self)
      self.phase =[0,0] 

   def delta_x(self, x):
      '''external transition function'''
      if x.port == self.IP["?push1"]: 
         if self.phase[0] == 0:
            self.phase[0] = 1 
            self.C['t1'].tL = Clock.tNow
            self.C['t1'].tN = Clock.tNow + self.toast_times['t1'].sample() # new sampling
      elif x.port == self.IP["?push2"]:
         if self.phase[1] == 0:
            self.phase[1] = 1 
            self.C['t2'].tL = Clock.tNow
            self.C['t2'].tN = Clock.tNow + self.toast_times['t2'].sample() # new sampling
      else:
         pass # ignore the 
         
   def delta_y(self):
      '''internal transition function'''
      if Clock.tNow == self.C['t1'].tN: 
         self.phase[0] = 0 
         self.C['t1'].tL = Clock.tNow
         self.C['t1'].tN = float('inf')
         return PortValue(self.OP["!pop1"], None)
      elif Clock.tNow == self.C['t2'].tN:
         self.phase[1] = 0 
         self.C['t2'].tL = Clock.tNow
         self.C['t2'].tN = float('inf')
         return PortValue(self.OP["!pop2"], None)
      else:
         raise Exception("Schedule error at %s!"%__function__())

   def state_to_s(self):
      ''' return the state into a string '''
      s = str(self.phase) + "," + CDEVS.state_to_s(self)
      return s 

def make_input_event(md, JSONarg=None):
   ''' a callback function for injection'''
   ipn = raw_input('input port name ?push1 or ?push2 >')
   if ipn in md.IP:
      ip = md.IP[ipn]
      return md, PortValue(ip)
   else:
      return None, None 

if __name__ == '__main__':
   print 'This example shows a coupled model "system" having two toaster "ts1" and "ts2" '
   print 'which can get started toasting by injection of "?push1" or "?push2", resectively'

   md = TwoSlotToaster("ts12", None) 
   engine = SimEngine(md, make_input_event)

   #---- setting StepByStep and DES simulation only ----
   engine.StepByStep = True
   engine.sfactor = float('inf')
   #----------------------------------------------------
   engine.runInteractiveMenu()
